package com.dragon.modules.yuegou.model.rbac;

import com.dragon.modules.yuegou.web.LinkedTree;
import com.dragon.modules.yuegou.web.Tree;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Objects;

/**
 * 数据权限的授权单元<br>
 * 数据单元的ID：数据单元ID定义：(D{busdId})G{groupId}<br>
 * 
 * @author liuwu
 *
 */
public class DbacData {

	public static final String ROOT_ID = "0";
	public static final String GROUP_ID_PREFIX = "G";
	public static final String BUSD_ID_PREFIX = "D";

	/**
	 * 数据单元ID
	 */
	protected final String id;

	/**
	 * 父数据单元ID
	 */
	@Nullable
	protected final String parentId;

	/**
	 * 数据单元名称
	 */
	protected final String name;

	@JsonCreator
	public DbacData(@JsonProperty("id") String id, @Nullable @JsonProperty("parentId") String parentId,
			@JsonProperty("name") String name) {
		super();
		this.id = id;
		this.parentId = parentId;
		this.name = name;
	}

	public DbacData(DbacData data) {
		super();
		this.id = data.id;
		this.parentId = data.parentId;
		this.name = data.name;
	}

	/**
	 * 根据商圈创建数据节点
	 * 
	 * @param busdId   商圈ID
	 * @param groupId  集团ID
	 * @param busdName 商圈名称
	 * @return 数据节点
	 */
	public static DbacData fromBusd(String busdId, String groupId, String busdName) {
		return new DbacData(BUSD_ID_PREFIX + busdId + GROUP_ID_PREFIX + groupId, GROUP_ID_PREFIX + groupId, busdName);
	}

	/**
	 * 根据集团创建数据节点
	 * 
	 * @param groupId   集团ID
	 * @param groupName 集团名称
	 * @return 数据节点
	 */
	public static DbacData fromGroup(String groupId, String groupName) {
		return new DbacData(GROUP_ID_PREFIX + groupId, ROOT_ID, groupName);
	}

	/**
	 * 创建集团数据单元ID
	 * 
	 * @param groupId 集团ID
	 * @return 数据单元ID
	 */
	public static String createGroupDataId(String groupId) {
		return GROUP_ID_PREFIX + groupId;
	}

	/**
	 * 创建商圈数据单元ID
	 * 
	 * @param busdId 商圈ID
	 * @return 数据单元ID
	 */
	public static String createBusdDataId(String busdId) {
		return BUSD_ID_PREFIX + busdId;
	}

	/**
	 * 根据数据ID得到数据单元对象
	 * 
	 * @param dataId 数据ID
	 * @return 数据单元对象
	 */
	public static DbacData key(String dataId) {
		return new DbacData(dataId, null, null);
	}

	/**
	 * 根节点
	 * 
	 * @return 构造一个根节点
	 */
	public static DbacData root() {
		return new DbacData(ROOT_ID, null, "根节点");
	}

	/**
	 * 获取数据单元ID
	 * 
	 * @return 数据单元ID
	 */
	public String getId() {
		return id;
	}

	/**
	 * 获取父数据单元ID
	 * 
	 * @return 父数据单元ID
	 */
	@Nullable
	public String getParentId() {
		return parentId;
	}

	/**
	 * 获取数据单元名称
	 * 
	 * @return 数据单元名称
	 */
	public String getName() {
		return name;
	}

	/**
	 * 判断是否是集团节点
	 * 
	 * @return true表示是集团节点，false表示不是集团节点
	 */
	@JsonIgnore
	public boolean isGroupNode() {
		return id.startsWith(GROUP_ID_PREFIX);
	}

	/**
	 * 判断是否是商圈节点
	 * 
	 * @return true表示是商圈节点，false表示不是商圈节点
	 */
	@JsonIgnore
	public boolean isBusdNode() {
		return id.startsWith(BUSD_ID_PREFIX);
	}

	/**
	 * 获取商圈ID
	 * 
	 * @return 商圈ID
	 */
	@Nullable
	public String busdId() {
		if (isBusdNode()) {
			int sp = id.indexOf(GROUP_ID_PREFIX);
			if (sp < 0) {
				throw new IllegalStateException("数据单元ID不符合范式");
			}
			return id.substring(1, sp);
		} else {
			// 目前来说，不是商圈节点，就是集团节点
			return null;
		}
	}

	/**
	 * 获取集团ID
	 * 
	 * @return 集团ID
	 */
	@Nullable
	public String groupId() {
		if (isBusdNode()) {
			int sp = id.indexOf(GROUP_ID_PREFIX);
			if (sp < 0) {
				throw new IllegalStateException("数据单元ID不符合范式");
			}
			return id.substring(sp + 1);
		} else if (isGroupNode()) {
			return id.substring(1);
		} else {
			// 目前来说，不是商圈节点，就是集团节点
			return null;
		}
	}

	@JsonIgnore
	public boolean isRoot() {
		return ROOT_ID.equals(id);
	}

	@Override
	public String toString() {
		return String.format("%s(%s)", name, id);
	}

	@Override
	public int hashCode() {
		return Objects.hash(id);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		DbacData other = (DbacData) obj;
		return Objects.equals(id, other.id);
	}

	/**
	 * 构造数据树
	 * 
	 * @param coll 集合
	 * @return 数据树
	 */
	public static <T extends DbacData> Tree<T> buildTree(Collection<T> coll) {
		return LinkedTree.build(coll, DbacData::isRoot, (e, r) -> r.getId().equals(e.getParentId()),
				(o1, o2) -> o1.getName().compareTo(o2.getName()));
	}
}
